poolModule = require 'generic-pool'
FTPClient = require 'ftp'
async = require 'async'
assert = require 'assert'
path = require 'path'
log = require('./log').getLogger('ftp')
fs = require 'fs'

#create the directory recursively
mkdirDirRec = (client,dirs,i,cb)->
  directory = ""
  return cb null unless i < dirs.length
  return mkdirDirRec client,dirs,i+1,cb if dirs[i] is ""
  directory += paths+'/' for paths,j in dirs when j<=i
  client.mkdir directory,(err,string)->
    return mkdirDirRec client,dirs,i+1,cb

# @option (<_object_>)
#   [for Pool]
#    <_string_>name.Default:'ftp'  <_user_>string  <_string_>password  <_string_>workingDirectory
#    <_int_>timewarning.Defalut:2000 <_int_>idleTimeoutMillis <_int_>poolSize
#   [for ftp]
#     <_string_>host.Default:"localhost" <_int_>port.Default:21 <_int_>connTimeout.Default:15000
#     <_function_>debug
class FtpConnection
  constructor:(option)->
    @timewarning = option.timewarning ? 2000
    @pool = poolModule.Pool {
      name :  option.name ? 'ftp'
      create : (callback)->
        client = new FTPClient()
        client.on 'ready',(err)->
          console.log err if err
          callback null,client
        client.on 'error',callback
        client.connect(option)
      destroy: (conn) -> 
        if typeof conn.destroy is 'function'
          conn.destroy()
        else
          conn.end()
      max: option.poolSize
      min: 0
      refreshIdle: false
      idleTimeoutMillis: option.idleTimeoutMillis ? 10000
    }

  exec: (command, callback) ->
    assert.ok typeof(command) is 'function' and typeof(callback) is 'function'
    @pool.acquire (err, client) =>
      return callback err, null if err
      startTime = new Date
      command client, (err, result) =>
        @pool.release client
        callback err, result

  # upload file !
  # Notice: it will create the directory recursively before upload
  upload:(instream,fullpath,callback)->
    assert.ok(typeof(fullpath) is "string")
    instream = fs.createReadStream(instream) if typeof(instream) is "string"
    instream.on "error",(err)->
      instream.destroy()
      callback err
    # ??? instream must pause before any async phrase
    instream.pause()
    op = (client,cb) ->
      dirs = path.dirname(fullpath).split('/')
      mkdirDirRec client,dirs,0,(err)->
        return cb err if err
        client.put instream,fullpath,cb
    @exec op, callback

  download:(filename,desc,callback)->
    op = (client,cb) ->client.get filename,(err,stream)->
      cb err if err
      stream.on 'close',()->  cb null
      stream.on 'error',(err)-> log.warn "ERROR during get(): #{err.stack? err.inspect err}"
      stream.pipe(fs.createWriteStream(desc))
    @exec op, callback

  status:(callback)->
    op = (client,cb) ->client.status cb
    @exec op, callback

ftpConfig = 
  production:
    host:'192.168.1.153'
    port: 2121
    user:'ftp.imgcache.153'
    password:'3Ger_q#t~_684013'
    workingDirectory:'/weixin'
    poolSize:10
  development:
    host:'192.168.1.153'
    port: 2121
    user:'ftp.imgcache.153'
    password:'3Ger_q#t~_684013'
    workingDirectory:'/weixin'
    poolSize:10
  test:
    host:'192.168.1.153'
    port: 2121
    user:'ftp.imgcache.153'
    password:'3Ger_q#t~_684013'
    workingDirectory:'/weixin'
    poolSize:10

ftpCon = new FtpConnection(ftpConfig[process.env['NODE_ENV'] ? 'test'])
exports.exec = ftpCon.exec.bind(ftpCon)
exports.upload = ftpCon.upload.bind(ftpCon)
exports.download = ftpCon.download.bind(ftpCon)
exports.status = ftpCon.status.bind(ftpCon)


exports.status (err, state)->
  console.log arguments
